package com.douya.common.utils;

import com.douya.common.enums.MinuteTruncateEnums;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;

/**
 * 说明:localtime,localDatetime,localDate相关工具类
 *
 * @Author 胡晨烨
 * @Date 2020/3/17
 */
public class LocalDataUtils {


    /**
     * 把localDateTime截取到对应的整分钟数，秒和毫秒为0
     *
     * @param localDateTime       接收的时间
     * @param minuteTruncateEnums 截取的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToMinutes(LocalDateTime localDateTime, MinuteTruncateEnums minuteTruncateEnums) {

        return localDateTime.with(ChronoField.MINUTE_OF_HOUR, (long) localDateTime.getMinute() / minuteTruncateEnums.getValue() * minuteTruncateEnums.getValue())
                .with(ChronoField.SECOND_OF_MINUTE, 0)
                .with(ChronoField.MILLI_OF_SECOND, 0);
    }

    /**
     * 把localDateTime截取到对应的整分钟数，秒和毫秒为0
     *
     * @param localTime           接收的时间
     * @param minuteTruncateEnums 截取的时间
     * @return 新生成的时间
     */
    public static LocalTime truncatedToMinutes(LocalTime localTime, MinuteTruncateEnums minuteTruncateEnums) {

        return localTime.with(ChronoField.MINUTE_OF_HOUR, (long) localTime.getMinute() / minuteTruncateEnums.getValue() * minuteTruncateEnums.getValue())
                .with(ChronoField.SECOND_OF_MINUTE, 0)
                .with(ChronoField.MILLI_OF_SECOND, 0);
    }


    /**
     * 截取到5分钟
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToFiveMinutes(LocalDateTime localDateTime) {
        return truncatedToMinutes(localDateTime, MinuteTruncateEnums.MINUTE_5);
    }

    /**
     * 截取到10分钟
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToTenMinutes(LocalDateTime localDateTime) {
        return truncatedToMinutes(localDateTime, MinuteTruncateEnums.MINUTE_10);
    }


    /**
     * 截取到整分钟
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToMinute(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.MINUTES);
    }

    /**
     * 截取到整分钟
     *
     * @param localTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalTime truncatedToMinute(LocalTime localTime) {
        return localTime.truncatedTo(ChronoUnit.MINUTES);
    }

    /**
     * 截取到整小时
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToHour(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.HOURS);
    }

    /**
     * 截取到整小时
     *
     * @param localTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalTime truncatedToHour(LocalTime localTime) {
        return localTime.truncatedTo(ChronoUnit.HOURS);
    }


    /**
     * 截取到0点
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToDay(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * 截取到0点
     *
     * @param localTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalTime truncatedToDay(LocalTime localTime) {
        return localTime.truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * 截取到本月第一天
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToMonth(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 截取到本月第一天
     *
     * @param localDate 接收的时间
     * @return 新生成的时间
     */
    public static LocalDate truncatedToMonth(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 截取到本月最后一天
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToMonthEnd(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 截取到本月最后一天
     *
     * @param localDate 接收的时间
     * @return 新生成的时间
     */
    public static LocalDate truncatedToMonthEnd(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 截取到今年最后一天
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToYearEnd(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.lastDayOfYear());
    }

    /**
     * 截取到鸡年最后一天
     *
     * @param localDate 接收的时间
     * @return 新生成的时间
     */
    public static LocalDate truncatedToYearEnd(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.lastDayOfYear());
    }

    /**
     * 截取到今年第一天
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToYear(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 截取到今年第一天
     *
     * @param localDate 接收的时间
     * @return 新生成的时间
     */
    public static LocalDate truncatedToYear(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 截取到周一
     *
     * @param localDateTime 接收的时间
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToMonday(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }

    /**
     * 截取到周一
     *
     * @param localDate 接收的时间
     * @return 新生成的时间
     */
    public static LocalDate truncatedToMonday(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }

    /**
     * 截取到周几(包含同一天）
     *
     * @param localDateTime 接收的时间
     * @param dayOfWeek     周几
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToWeekDay(LocalDateTime localDateTime, DayOfWeek dayOfWeek) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.previousOrSame(dayOfWeek));
    }

    /**
     * 截取到周几(包含同一天）
     *
     * @param localDate 接收的时间
     * @param dayOfWeek 周几
     * @return 新生成的时间
     */
    public static LocalDate truncatedToWeekDay(LocalDate localDate, DayOfWeek dayOfWeek) {
        return localDate.with(TemporalAdjusters.previousOrSame(dayOfWeek));
    }

    /**
     * 截取到下周几(包含同一天)
     *
     * @param localDateTime 接收的时间
     * @param dayOfWeek     周几
     * @return 新生成的时间
     */
    public static LocalDateTime truncatedToNextWeekDay(LocalDateTime localDateTime, DayOfWeek dayOfWeek) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS).with(TemporalAdjusters.nextOrSame(dayOfWeek));
    }

    /**
     * 截取到下周几(包含同一天)
     *
     * @param localDate 接收的时间
     * @param dayOfWeek 周几
     * @return 新生成的时间
     */
    public static LocalDate truncatedToNextWeekDay(LocalDate localDate, DayOfWeek dayOfWeek) {
        return localDate.with(TemporalAdjusters.nextOrSame(dayOfWeek));
    }

    /**
     * 格式化时间
     *
     * @param localDateTime 接收的时间
     * @param pattern       格式化格式
     * @return 新生成的时间
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 格式化时间
     *
     * @param localDate 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static String format(LocalDate localDate, String pattern) {
        return localDate.format(DateTimeFormatter.ofPattern(pattern));
    }


    /**
     * 格式化时间
     *
     * @param localTime 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static String format(LocalTime localTime, String pattern) {
        return localTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 按照默认的格式，尝试进行日期转化
     *
     * @param localDate 时间字符串
     * @return 转化后的日期
     */
    public static LocalDate parseDateWithDefaultPatterns(String localDate) {
        String[] patterns = new String[]{"yyyy/MM/dd", "yyyy-MM-dd", "yyyyMMdd"};
        for (String pattern : patterns) {
            try {
                return parseDate(localDate, pattern);
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    /**
     * 按照默认的格式，尝试进行日期转化
     *
     * @param localDateTime 时间字符串
     * @return 转化后的日期
     */
    public static LocalDateTime parseDateTimeWithDefaultPatterns(String localDateTime) {
        String[] patterns = new String[]{"yyyy/MM/dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss", "yyyyMMddHHmmss"};
        for (String pattern : patterns) {
            try {
                return parseDateTime(localDateTime, pattern);
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    /**
     * 解析时间,支持年yyyy,月yyyyMM,yyyy-MM,yyyy/MM转换成对应的一月一号
     *
     * @param localDate 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static LocalDate parseDate(String localDate, String pattern) {
        if ("yyyy".equals(pattern)) {
            return LocalDate.of(Integer.parseInt(localDate), 1, 1);
        } else if ("yyyyMM".equals(pattern) || "yyyy-MM".equals(pattern) || "yyyy/MM".equals(pattern)) {
            return LocalDate.parse(localDate + "01", DateTimeFormatter.ofPattern(pattern + "dd"));
        } else {
            return LocalDate.parse(localDate, DateTimeFormatter.ofPattern(pattern));
        }
    }

    /**
     * 解析时间
     *
     * @param localTime 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static LocalTime parseTime(String localTime, String pattern) {
        return LocalTime.parse(localTime, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 解析时间
     *
     * @param localDateTime 接收的时间
     * @param pattern       格式化格式
     * @return 新生成的时间
     */
    public static LocalDateTime parseDateTime(String localDateTime, String pattern) {
        if ("yyyyMMdd".equals(pattern) || "yyyy-MM-dd".equals(pattern) || "yyyy/MM/dd".equals(pattern)) {
            return LocalDateTime.of(parseDate(localDateTime, pattern), LocalTime.MIN);
        } else {
            return LocalDateTime.parse(localDateTime, DateTimeFormatter.ofPattern(pattern));
        }

    }

    /**
     * 获取从 January 1, 1970 UTC到现在的秒数
     *
     * @param localDate      接收的时间
     * @param truncatedToDay true:截取到当天0点,false:当前时间
     * @return 秒
     */
    public static long getSeconds(LocalDate localDate, boolean truncatedToDay) {

        return truncatedToDay ? localDate.atStartOfDay().toEpochSecond(ZoneOffset.of("+8"))
                : localDate.atTime(LocalTime.now()).toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * 获取从 January 1, 1970 UTC到现在的毫秒数
     *
     * @param localDate      接收的时间
     * @param truncatedToDay true:截取到当天0点,false:当前时间
     * @return 毫秒
     */
    public static long getMilliSeconds(LocalDate localDate, boolean truncatedToDay) {
        return truncatedToDay ? localDate.atStartOfDay().toEpochSecond(ZoneOffset.of("+8"))
                : localDate.atTime(LocalTime.now()).toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * 获取从 January 1, 1970 UTC到现在的秒数
     *
     * @param localDateTime 接收的时间
     * @return 秒
     */
    public static long getSeconds(LocalDateTime localDateTime) {
        return localDateTime.toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * 获取从 January 1, 1970 UTC到现在的毫秒数
     *
     * @param localDateTime 接收的时间
     * @return 毫秒
     */
    public static long getMilliSeconds(LocalDateTime localDateTime) {
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * 判断一个日期是否周末
     *
     * @param localDateTime 接收的时间
     * @return 是否周末
     */
    public static boolean isWeekend(LocalDateTime localDateTime) {
        return isWeekend(localDateTime.toLocalDate());
    }

    /**
     * 判断一个日期是否周末
     *
     * @param localDate 接收的时间
     * @return 是否周末
     */
    public static boolean isWeekend(LocalDate localDate) {
        return localDate.getDayOfWeek() == DayOfWeek.SATURDAY || localDate.getDayOfWeek() == DayOfWeek.SUNDAY;
    }

    /**
     * 判断一个日期是否工作日
     *
     * @param localDateTime 接收的时间
     * @return 是否工作日
     */
    public static boolean isWorkDay(LocalDateTime localDateTime) {
        return !isWeekend(localDateTime.toLocalDate());
    }

    /**
     * 判断一个日期是否工作日
     *
     * @param localDate 接收的时间
     * @return 是否工作日
     */
    public static boolean isWorkDay(LocalDate localDate) {
        return !isWeekend(localDate);
    }

    /**
     * 根据起始时间获取中间月份集合
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @return List<string> 数组里面的每一项是从开始月份到结束月份排列 yyyy-MM
     */
    public static List<LocalDate> monthBetween(LocalDate startTime, LocalDate endTime) {
        startTime = LocalDataUtils.truncatedToMonth(startTime);
        endTime = LocalDataUtils.truncatedToMonth(endTime);
        ArrayList<LocalDate> result = new ArrayList<LocalDate>();
        while (!startTime.isAfter(endTime)) {
            result.add(startTime);
            startTime = startTime.plusMonths(1);
        }
        return result;
    }


    /**
     * 根据起始时间获取中间日期集合，包含开始结束
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @return 日期集合
     */
    public static List<LocalDate> daysBetween(LocalDate startTime, LocalDate endTime) {
        ArrayList<LocalDate> result = new ArrayList<>();
        while (!startTime.isAfter(endTime)) {
            result.add(startTime);
            startTime = startTime.plusDays(1);
        }
        return result;
    }

    /**
     * 解析时间,支持年yyyy,月yyyyMM,yyyy-MM,yyyy/MM转换成对应的一月一号
     *
     * @param localDate 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static MonthDay parseMonthDay(String localDate, String pattern) {

        return MonthDay.parse(localDate, DateTimeFormatter.ofPattern(pattern));


    }

    /**
     * 解析时间
     *
     * @param localDate 接收的时间
     * @param pattern   格式化格式
     * @return 新生成的时间
     */
    public static String formatMonthDay(MonthDay localDate, String pattern) {

        return localDate.format(DateTimeFormatter.ofPattern(pattern));


    }
}
